package com.gjy.spring.boot3;

import com.gjy.spring.boot.HelloBeanA;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;

import java.util.Arrays;

/**
 * 运行时添加参数 --server.port=8080 debug
 *
 * @author 宫静雨
 * @version 1.0
 * @since 2023-12-18 10:32:13
 */
@SuppressWarnings("all")
public class Boot3App {

    public static void main(String[] args) throws Exception {

        SpringApplication app = new SpringApplication();
        app.setSources(Sets.newHashSet(Lists.newArrayList("com.gjy.spring.a03")));
        app.addInitializers(initializers -> {
            System.out.println("初始化器增强: " + initializers);
        });

        System.out.println(">>>>>>>>>>>>>>> 2. 封装启动 args");
        DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);

        System.out.println(">>>>>>>>>>>>>>> 8. 创建容器");
        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

        System.out.println(">>>>>>>>>>>>>>> 9. 准备容器"); // 回调初始化器
        for (ApplicationContextInitializer initializer : app.getInitializers()) {
            initializer.initialize(context);
        }

        System.out.println(">>>>>>>>>>>>>>> 10. 加载 Bean 定义"); // 从各种来源加载各种不同的Bean定义
        DefaultListableBeanFactory defaultListableBeanFactory = context.getDefaultListableBeanFactory();
        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(defaultListableBeanFactory);
        reader.registerBean(Config.class);
        XmlBeanDefinitionReader r2 = new XmlBeanDefinitionReader(defaultListableBeanFactory);
        r2.loadBeanDefinitions("classpath:b01.xml");//r2.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        ClassPathBeanDefinitionScanner r3 = new ClassPathBeanDefinitionScanner(defaultListableBeanFactory);
        r3.scan("com.gjy.spring.a01");

        System.out.println(">>>>>>>>>>>>>>> 11. refresh 容器"); // refresh 后才能验证 Bean定义有没有加入
        context.refresh();

        for (String s : context.getBeanDefinitionNames()) {
            System.out.println("s = " + s + "\t来源: " + context.getBeanDefinition(s).getResourceDescription());
        }
        System.out.println(">>>>>>>>>>>>>>> 12. 执行 runner"); // 数据预加载, CommandLineRunner ApplicationRunner
        for (CommandLineRunner runner : context.getBeansOfType(CommandLineRunner.class).values()) {
            runner.run(args);
        }
        for (ApplicationRunner runner : context.getBeansOfType(ApplicationRunner.class).values()) {
            runner.run(arguments);
        }
        context.close();
    }

    private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
        GenericApplicationContext context = null;
        switch (type) {
            case NONE:
                context = new AnnotationConfigApplicationContext();
                break;
            case SERVLET:
                context = new AnnotationConfigServletWebServerApplicationContext();
                break;
            case REACTIVE:
                context = new AnnotationConfigReactiveWebServerApplicationContext();
                break;
            default:
                break;
        }
        return context;
    }

    @Configuration
    static class Config {
        @Bean
        public HelloBeanA helloBeanA() {
            return new HelloBeanA();
        }

        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public CommandLineRunner commandLineRunner() {
            return new CommandLineRunner() {
                @Override
                public void run(String... args) throws Exception { // main 方法的参数
                    System.out.println("\"command line runner\" = " + "command line runner: " + Arrays.toString(args));
                }
            };
        }

        @Bean
        public ApplicationRunner applicationRunner() {
            return new ApplicationRunner() {
                @Override
                public void run(ApplicationArguments args) throws Exception { // 封装好后的参数
                    System.out.println("\"application runner\" = " + "application runner: " + Arrays.toString(args.getSourceArgs()));
                    System.out.println("args.getOptionNames() = " + args.getOptionNames());
                    System.out.println("args.getNonOptionArgs() = " + args.getNonOptionArgs());
                }
            };
        }
    }
}
